/*****************************************************************************
 * Copyright (C) Stacy Curl. All rights reserved.                            *
 * ------------------------------------------------------------------------- *
 * The software in this package is published under the terms of the BSD      *
 * style license a copy of which has been included with this distribution in *
 * the LICENSE.txt file.                                                     *
 *****************************************************************************/
package picounit;

import java.lang.reflect.Constructor;

import junit.framework.Test;

public class PicoUnit implements JUnitTestGenerator, Registry {
	private final PicoUnitAPI implementation;

	/** @deprecated Please provide a name for the test suite */
	public PicoUnit() {
		this("", getDefaultType());
	}

	public PicoUnit(String name) {
		this(name, getDefaultType());
	}

	public PicoUnit(String name, Class type) {
		implementation = createImplementation(name, type);
	}

	public Test generateJUnitTest() {
		return implementation.generateJUnitTest();
	}

	public Test generateJUnitTest(JUnitTestGenerator generator) {
		return implementation.generateJUnitTest(generator);
	}

	public Test generateJUnitTest(Class startingClass) {
		return implementation.generateJUnitTest(startingClass);
	}

	public Test generateSingleJUnitTest(Class testClass) {
		return implementation.generateSingleJUnitTest(testClass);
	}

	/** @deprecated Please use the constructor to specify a type */
	public PicoUnit setType(Class type) {
		implementation.setType(type);

		return this;
	}

	public void register(Class type, Object instance) {
		this.implementation.register(type, instance);
	}

	public void register(Class type, Class implementation) {
		this.implementation.register(type, implementation);
	}

	public void register(Class implementation) {
		this.implementation.register(implementation);
	}
	
	public void register(String key, boolean value) {
		this.implementation.register(key, value);
	}
	
	public void register(String key, byte value) {
		this.implementation.register(key, value);
	}
	
	public void register(String key, char value) {
		this.implementation.register(key, value);
	}
	
	public void register(String key, double value) {
		this.implementation.register(key, value);
	}
	
	public void register(String key, float value) {
		this.implementation.register(key, value);
	}
	
	public void register(String key, int value) {
		this.implementation.register(key, value);
	}
	
	public void register(String key, long value) {
		this.implementation.register(key, value);
	}
	
	public void register(String key, short value) {
		this.implementation.register(key, value);
	}
	
	public void register(String key, String value) {
		this.implementation.register(key, value);
	}

	private static PicoUnitAPI createImplementation(String name, Class type) {
		Class implementationClass = getImplementationClass();

		try {
			Constructor constructor = implementationClass.getConstructor(new Class[] {
				String.class, Class.class});

			return (PicoUnitAPI) constructor.newInstance(new Object[] {name, type});
		}
		catch (Exception e) {
			throw new PicoUnitException(e);
		}
	}

	private static Class getImplementationClass() {
		return getClassProperty("picounit.implementation", "picounit.impl.PicoUnitImpl");
	}

	private static Class getDefaultType() {
		return getClassProperty("picounit.default.test.type", "picounit.Test");
	}

	private static Class getClassProperty(String name, String defaultValue) {
		try {
			return Class.forName(System.getProperty(name, defaultValue));
		}
		catch (ClassNotFoundException classNotFoundException) {
			throw new PicoUnitException(classNotFoundException);
		}
	}
}
